package com.qunar.wan.service;

import com.google.common.cache.*;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.qunar.wan.common_api.model.Classify;
import com.qunar.wan.common_api.model.SubClassify;
import com.qunar.wan.common_api.service.CacheService;
import com.qunar.wan.common_api.service.ClassifyService;
import com.qunar.wan.common_api.service.SubClassifyService;
import com.qunar.wan.common_api.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * Created by cyoung on 12/25/13.
 */
@Service("cacheService")
public class CacheServiceImpl implements CacheService {
    private Logger logger = LoggerFactory.getLogger(getClass());
    @Resource
    private SubClassifyService subClassifyService;
    @Resource
    private ClassifyService classifyService;
    @Resource
    private UserService userService;

    /**
     * 单个大分类下所有子分类
     */
    private static final String SUBCLAS_PREFIX = "subs";
    /**
     * 单个子分类
     */
    private static final String SINGLE_SUBCLA_PREFIX = "sub";
    /**
     * 单个大分类
     */
    private static final String SINGLE_CLA_PREFIX = "cla";
    /**
     * 所有大分类
     */
    private static final String ALL_CLAS_PREFIX = "clas";
    /**
     * 所有分类信息
     */
    private static final String ALL_DATA_PREFIX = "allData";

    private LoadingCache<String, Object> caches;

    @PostConstruct
    public void initCache() {
        caches = CacheBuilder.newBuilder().maximumSize(500)
                .recordStats()
                .expireAfterWrite(60 * 60 * 2, TimeUnit.SECONDS)
                .removalListener(new RemovalListener<String, Object>() {
                    @Override
                    public void onRemoval(RemovalNotification<String, Object> notification) {
                        logger.warn("remove:{}&{},cause:{}", notification.getKey(), notification.getValue(), notification.getCause());
                    }
                }).refreshAfterWrite(60 * 60, TimeUnit.SECONDS).build(new CacheLoader<String, Object>() {
                    //刷新单个缓存时可以对value进行操作
                    @Override
                    public ListenableFuture<Object> reload(String key, Object value) throws Exception {
                        return Futures.immediateFuture(value);
                    }

                    //key不存在时返回的值,并且会将键值加入cache
                    @Override
                    public Object load(String key) throws Exception {
                        if (key.startsWith(ALL_DATA_PREFIX)) {
                            return classifyService.selectAllClassifyAndSub();
                        }
                        if (key.startsWith(ALL_CLAS_PREFIX)) {
                            return classifyService.selectAll();
                        }
                        if (key.startsWith(SINGLE_CLA_PREFIX)) {
                            int claId = Integer.parseInt(key.substring(SINGLE_CLA_PREFIX.length(), key.length()));
                            return classifyService.selectClassifyById(claId);
                        }
                        if (key.startsWith(SUBCLAS_PREFIX)) {
                            int supClaId = Integer.parseInt(key.substring(SUBCLAS_PREFIX.length(), key.length()));
                            return subClassifyService.selectListBySupId(supClaId);
                        }
                        if (key.startsWith(SINGLE_SUBCLA_PREFIX)) {
                            int subClaId = Integer.parseInt(key.substring(SINGLE_SUBCLA_PREFIX.length(), key.length()));
                            return subClassifyService.selectSubClassifyById(subClaId, false);
                        }
//                         if(key.startsWith(STAR_USER_PREFIX)){
//                             /**缓存5个user*/
//                             return  userService.selectStarUser(STARUSER_NUM) ;
//                         }
                        return null;
                    }
                });
    }

    @Override
    public List<Object> readAllClassisfiesCache() {
        try {
            return (List<Object>) caches.get(ALL_DATA_PREFIX);
        } catch (ExecutionException e) {
            logger.error("readAllClassisfiesCache读取缓存异常{}", e);
            return classifyService.selectAllClassifyAndSub();
        }
    }

    @Override
    public SubClassify readSingleSubClassifyCache(int subId) {
        try {
            return (SubClassify) caches.get(SINGLE_SUBCLA_PREFIX + subId);
        } catch (ExecutionException e) {
            logger.error("readSingleSubClassifyCache读取缓存异常{}", e);
            return subClassifyService.selectSubClassifyById(subId, false);
        }
    }

    @Override
    public Classify readSingleClassifyCache(int claId) {
        try {
            return (Classify) caches.get(SINGLE_CLA_PREFIX + claId);
        } catch (ExecutionException e) {
            logger.error("readStarusersCache读取缓存异常{}", e);
            return classifyService.selectClassifyById(claId);
        }
    }

    @Override
    public List<SubClassify> readSubsCache(int supId) {
        try {
            return (List<SubClassify>) caches.get(SUBCLAS_PREFIX + supId);
        } catch (ExecutionException e) {
            logger.error("readSubsCache读取缓存异常{}", e);
            return subClassifyService.selectListBySupId(supId);
        }
    }

    @Override
    public List<Classify> readClasCache() {

        try {
            return (List<Classify>) caches.get(ALL_CLAS_PREFIX);

        } catch (ExecutionException e) {
            logger.error("readAllClasCache读取缓存异常{}", e);
            return classifyService.selectAll();
        }
    }

    @Override
    public void refreshAllClassisfiesCache() {
//        caches.refresh(ALL_DATA_PREFIX);
        caches.invalidate(ALL_DATA_PREFIX);
    }

    @Override
    public void refreshSingleSubClassifyCache(int subId) {
//        caches.refresh(SINGLE_SUBCLA_PREFIX+subId);
        caches.invalidate(SINGLE_SUBCLA_PREFIX + subId);
    }

    @Override
    public void refreshSingleClassifyCache(int claId) {
//        caches.refresh(SINGLE_CLA_PREFIX+claId);
        caches.invalidate(SINGLE_CLA_PREFIX + claId);
    }

    @Override
    public void refreshSubsCache(int supId) {
//        caches.refresh(SUBCLAS_PREFIX+supId);
        caches.invalidate(SUBCLAS_PREFIX + supId);
    }

    @Override
    public void refreshClasCache() {
//        caches.refresh(ALL_CLAS_PREFIX);
        caches.invalidate(ALL_CLAS_PREFIX);
    }

}
